<?xml version="1.0" encoding="ascii"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>digichef.tagging.tests.tests</title>
  <link rel="stylesheet" href="epydoc.css" type="text/css" />
  <script type="text/javascript" src="epydoc.js"></script>
</head>

<body bgcolor="white" text="black" link="blue" vlink="#204080"
      alink="#204080">
<!-- ==================== NAVIGATION BAR ==================== -->
<table class="navbar" border="0" width="100%" cellpadding="0"
       bgcolor="#a0c0ff" cellspacing="0">
  <tr valign="middle">

  <!-- Tree link -->
      <th>&nbsp;&nbsp;&nbsp;<a
        href="module-tree.html">Trees</a>&nbsp;&nbsp;&nbsp;</th>

  <!-- Index link -->
      <th>&nbsp;&nbsp;&nbsp;<a
        href="identifier-index.html">Indices</a>&nbsp;&nbsp;&nbsp;</th>

  <!-- Help link -->
      <th>&nbsp;&nbsp;&nbsp;<a
        href="help.html">Help</a>&nbsp;&nbsp;&nbsp;</th>

      <th class="navbar" width="100%"></th>
  </tr>
</table>
<table width="100%" cellpadding="0" cellspacing="0">
  <tr valign="top">
    <td width="100%">
      <span class="breadcrumbs">
        <a href="digichef-module.html">Package&nbsp;digichef</a> ::
        <a href="digichef.tagging-module.html">Package&nbsp;tagging</a> ::
        <a href="digichef.tagging.tests-module.html">Package&nbsp;tests</a> ::
        Module&nbsp;tests
      </span>
    </td>
    <td>
      <table cellpadding="0" cellspacing="0">
        <!-- hide/show private -->
        <tr><td align="right"><span class="options">[<a href="javascript:void(0);" class="privatelink"
    onclick="toggle_private();">hide&nbsp;private</a>]</span></td></tr>
        <tr><td align="right"><span class="options"
            >[<a href="frames.html" target="_top">frames</a
            >]&nbsp;|&nbsp;<a href="digichef.tagging.tests.tests-module.html"
            target="_top">no&nbsp;frames</a>]</span></td></tr>
      </table>
    </td>
  </tr>
</table>
<!-- ==================== MODULE DESCRIPTION ==================== -->
<h1 class="epydoc">Module tests</h1><p class="nomargin-top"><span class="codelink"><a href="digichef.tagging.tests.tests-pysrc.html">source&nbsp;code</a></span></p>
<pre class="literalblock">

&gt;&gt;&gt; import os
&gt;&gt;&gt; from django import forms
&gt;&gt;&gt; from django.db.models import Q
&gt;&gt;&gt; from tagging.forms import TagField
&gt;&gt;&gt; from tagging import settings
&gt;&gt;&gt; from tagging.models import Tag, TaggedItem
&gt;&gt;&gt; from tagging.tests.models import Article, Link, Perch, Parrot, FormTest
&gt;&gt;&gt; from tagging.utils import calculate_cloud, get_tag_list, get_tag, parse_tag_input
&gt;&gt;&gt; from tagging.utils import LINEAR

#############
# Utilities #
#############

# Tag input ###################################################################

# Simple space-delimited tags
&gt;&gt;&gt; parse_tag_input('one')
[u'one']
&gt;&gt;&gt; parse_tag_input('one two')
[u'one', u'two']
&gt;&gt;&gt; parse_tag_input('one two three')
[u'one', u'three', u'two']
&gt;&gt;&gt; parse_tag_input('one one two two')
[u'one', u'two']

# Comma-delimited multiple words - an unquoted comma in the input will trigger
# this.
&gt;&gt;&gt; parse_tag_input(',one')
[u'one']
&gt;&gt;&gt; parse_tag_input(',one two')
[u'one two']
&gt;&gt;&gt; parse_tag_input(',one two three')
[u'one two three']
&gt;&gt;&gt; parse_tag_input('a-one, a-two and a-three')
[u'a-one', u'a-two and a-three']

# Double-quoted multiple words - a completed quote will trigger this.
# Unclosed quotes are ignored.
&gt;&gt;&gt; parse_tag_input('&quot;one')
[u'one']
&gt;&gt;&gt; parse_tag_input('&quot;one two')
[u'one', u'two']
&gt;&gt;&gt; parse_tag_input('&quot;one two three')
[u'one', u'three', u'two']
&gt;&gt;&gt; parse_tag_input('&quot;one two&quot;')
[u'one two']
&gt;&gt;&gt; parse_tag_input('a-one &quot;a-two and a-three&quot;')
[u'a-one', u'a-two and a-three']

# No loose commas - split on spaces
&gt;&gt;&gt; parse_tag_input('one two &quot;thr,ee&quot;')
[u'one', u'thr,ee', u'two']

# Loose commas - split on commas
&gt;&gt;&gt; parse_tag_input('&quot;one&quot;, two three')
[u'one', u'two three']

# Double quotes can contain commas
&gt;&gt;&gt; parse_tag_input('a-one &quot;a-two, and a-three&quot;')
[u'a-one', u'a-two, and a-three']
&gt;&gt;&gt; parse_tag_input('&quot;two&quot;, one, one, two, &quot;one&quot;')
[u'one', u'two']

# Bad users! Naughty users!
&gt;&gt;&gt; parse_tag_input(None)
[]
&gt;&gt;&gt; parse_tag_input('')
[]
&gt;&gt;&gt; parse_tag_input('&quot;')
[]
&gt;&gt;&gt; parse_tag_input('&quot;&quot;')
[]
&gt;&gt;&gt; parse_tag_input('&quot;' * 7)
[]
&gt;&gt;&gt; parse_tag_input(',,,,,,')
[]
&gt;&gt;&gt; parse_tag_input('&quot;,&quot;,&quot;,&quot;,&quot;,&quot;,&quot;,&quot;')
[u',']
&gt;&gt;&gt; parse_tag_input('a-one &quot;a-two&quot; and &quot;a-three')
[u'a-one', u'a-three', u'a-two', u'and']

# Normalised Tag list input ###################################################
&gt;&gt;&gt; cheese = Tag.objects.create(name='cheese')
&gt;&gt;&gt; toast = Tag.objects.create(name='toast')
&gt;&gt;&gt; get_tag_list(cheese)
[&lt;Tag: cheese&gt;]
&gt;&gt;&gt; get_tag_list('cheese toast')
[&lt;Tag: cheese&gt;, &lt;Tag: toast&gt;]
&gt;&gt;&gt; get_tag_list('cheese,toast')
[&lt;Tag: cheese&gt;, &lt;Tag: toast&gt;]
&gt;&gt;&gt; get_tag_list([])
[]
&gt;&gt;&gt; get_tag_list(['cheese', 'toast'])
[&lt;Tag: cheese&gt;, &lt;Tag: toast&gt;]
&gt;&gt;&gt; get_tag_list([cheese.id, toast.id])
[&lt;Tag: cheese&gt;, &lt;Tag: toast&gt;]
&gt;&gt;&gt; get_tag_list(['cheese', 'toast', '\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91'])
[&lt;Tag: cheese&gt;, &lt;Tag: toast&gt;]
&gt;&gt;&gt; get_tag_list([cheese, toast])
[&lt;Tag: cheese&gt;, &lt;Tag: toast&gt;]
&gt;&gt;&gt; get_tag_list((cheese, toast))
(&lt;Tag: cheese&gt;, &lt;Tag: toast&gt;)
&gt;&gt;&gt; get_tag_list(Tag.objects.filter(name__in=['cheese', 'toast']))
[&lt;Tag: cheese&gt;, &lt;Tag: toast&gt;]
&gt;&gt;&gt; get_tag_list(['cheese', toast])
Traceback (most recent call last):
    ...
ValueError: If a list or tuple of tags is provided, they must all be tag names, Tag objects or Tag ids.
&gt;&gt;&gt; get_tag_list(29)
Traceback (most recent call last):
    ...
ValueError: The tag input given was invalid.

# Normalised Tag input
&gt;&gt;&gt; get_tag(cheese)
&lt;Tag: cheese&gt;
&gt;&gt;&gt; get_tag('cheese')
&lt;Tag: cheese&gt;
&gt;&gt;&gt; get_tag(cheese.id)
&lt;Tag: cheese&gt;
&gt;&gt;&gt; get_tag('mouse')

# Tag clouds ##################################################################
&gt;&gt;&gt; tags = []
&gt;&gt;&gt; for line in open(os.path.join(os.path.dirname(__file__), 'tags.txt')).readlines():
...     name, count = line.rstrip().split()
...     tag = Tag(name=name)
...     tag.count = int(count)
...     tags.append(tag)

&gt;&gt;&gt; sizes = {}
&gt;&gt;&gt; for tag in calculate_cloud(tags, steps=5):
...     sizes[tag.font_size] = sizes.get(tag.font_size, 0) + 1

# This isn't a pre-calculated test, just making sure it's consistent
&gt;&gt;&gt; sizes
{1: 48, 2: 30, 3: 19, 4: 15, 5: 10}

&gt;&gt;&gt; sizes = {}
&gt;&gt;&gt; for tag in calculate_cloud(tags, steps=5, distribution=LINEAR):
...     sizes[tag.font_size] = sizes.get(tag.font_size, 0) + 1

# This isn't a pre-calculated test, just making sure it's consistent
&gt;&gt;&gt; sizes
{1: 97, 2: 12, 3: 7, 4: 2, 5: 4}

&gt;&gt;&gt; calculate_cloud(tags, steps=5, distribution='cheese')
Traceback (most recent call last):
    ...
ValueError: Invalid distribution algorithm specified: cheese.

###########
# Tagging #
###########

# Basic tagging ###############################################################

&gt;&gt;&gt; dead = Parrot.objects.create(state='dead')
&gt;&gt;&gt; Tag.objects.update_tags(dead, 'foo,bar,&quot;ter&quot;')
&gt;&gt;&gt; Tag.objects.get_for_object(dead)
[&lt;Tag: bar&gt;, &lt;Tag: foo&gt;, &lt;Tag: ter&gt;]
&gt;&gt;&gt; Tag.objects.update_tags(dead, '&quot;foo&quot; bar &quot;baz&quot;')
&gt;&gt;&gt; Tag.objects.get_for_object(dead)
[&lt;Tag: bar&gt;, &lt;Tag: baz&gt;, &lt;Tag: foo&gt;]
&gt;&gt;&gt; Tag.objects.add_tag(dead, 'foo')
&gt;&gt;&gt; Tag.objects.get_for_object(dead)
[&lt;Tag: bar&gt;, &lt;Tag: baz&gt;, &lt;Tag: foo&gt;]
&gt;&gt;&gt; Tag.objects.add_tag(dead, 'zip')
&gt;&gt;&gt; Tag.objects.get_for_object(dead)
[&lt;Tag: bar&gt;, &lt;Tag: baz&gt;, &lt;Tag: foo&gt;, &lt;Tag: zip&gt;]
&gt;&gt;&gt; Tag.objects.add_tag(dead, '    ')
Traceback (most recent call last):
    ...
AttributeError: No tags were given: &quot;    &quot;.
&gt;&gt;&gt; Tag.objects.add_tag(dead, 'one two')
Traceback (most recent call last):
    ...
AttributeError: Multiple tags were given: &quot;one two&quot;.

# Note that doctest in Python 2.4 (and maybe 2.5?) doesn't support non-ascii
# characters in output, so we're displaying the repr() here.
&gt;&gt;&gt; Tag.objects.update_tags(dead, '\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91')
&gt;&gt;&gt; repr(Tag.objects.get_for_object(dead))
'[&lt;Tag: \xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91&gt;]'

&gt;&gt;&gt; Tag.objects.update_tags(dead, None)
&gt;&gt;&gt; Tag.objects.get_for_object(dead)
[]

# Using a model's TagField
&gt;&gt;&gt; f1 = FormTest.objects.create(tags=u'test3 test2 test1')
&gt;&gt;&gt; Tag.objects.get_for_object(f1)
[&lt;Tag: test1&gt;, &lt;Tag: test2&gt;, &lt;Tag: test3&gt;]
&gt;&gt;&gt; f1.tags = u'test4'
&gt;&gt;&gt; f1.save()
&gt;&gt;&gt; Tag.objects.get_for_object(f1)
[&lt;Tag: test4&gt;]
&gt;&gt;&gt; f1.tags = ''
&gt;&gt;&gt; f1.save()
&gt;&gt;&gt; Tag.objects.get_for_object(f1)
[]

# Forcing tags to lowercase
&gt;&gt;&gt; settings.FORCE_LOWERCASE_TAGS = True
&gt;&gt;&gt; Tag.objects.update_tags(dead, 'foO bAr Ter')
&gt;&gt;&gt; Tag.objects.get_for_object(dead)
[&lt;Tag: bar&gt;, &lt;Tag: foo&gt;, &lt;Tag: ter&gt;]
&gt;&gt;&gt; Tag.objects.update_tags(dead, 'foO bAr baZ')
&gt;&gt;&gt; Tag.objects.get_for_object(dead)
[&lt;Tag: bar&gt;, &lt;Tag: baz&gt;, &lt;Tag: foo&gt;]
&gt;&gt;&gt; Tag.objects.add_tag(dead, 'FOO')
&gt;&gt;&gt; Tag.objects.get_for_object(dead)
[&lt;Tag: bar&gt;, &lt;Tag: baz&gt;, &lt;Tag: foo&gt;]
&gt;&gt;&gt; Tag.objects.add_tag(dead, 'Zip')
&gt;&gt;&gt; Tag.objects.get_for_object(dead)
[&lt;Tag: bar&gt;, &lt;Tag: baz&gt;, &lt;Tag: foo&gt;, &lt;Tag: zip&gt;]
&gt;&gt;&gt; Tag.objects.update_tags(dead, None)
&gt;&gt;&gt; f1.tags = u'TEST5'
&gt;&gt;&gt; f1.save()
&gt;&gt;&gt; Tag.objects.get_for_object(f1)
[&lt;Tag: test5&gt;]
&gt;&gt;&gt; f1.tags
u'test5'

# Retrieving tags by Model ####################################################

&gt;&gt;&gt; Tag.objects.usage_for_model(Parrot)
[]
&gt;&gt;&gt; parrot_details = (
...     ('pining for the fjords', 9, True,  'foo bar'),
...     ('passed on',             6, False, 'bar baz ter'),
...     ('no more',               4, True,  'foo ter'),
...     ('late',                  2, False, 'bar ter'),
... )

&gt;&gt;&gt; for state, perch_size, perch_smelly, tags in parrot_details:
...     perch = Perch.objects.create(size=perch_size, smelly=perch_smelly)
...     parrot = Parrot.objects.create(state=state, perch=perch)
...     Tag.objects.update_tags(parrot, tags)

&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_model(Parrot, counts=True)]
[(u'bar', 3), (u'baz', 1), (u'foo', 2), (u'ter', 3)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_model(Parrot, min_count=2)]
[(u'bar', 3), (u'foo', 2), (u'ter', 3)]

# Limiting results to a subset of the model
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_model(Parrot, counts=True, filters=dict(state='no more'))]
[(u'foo', 1), (u'ter', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_model(Parrot, counts=True, filters=dict(state__startswith='p'))]
[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_model(Parrot, counts=True, filters=dict(perch__size__gt=4))]
[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_model(Parrot, counts=True, filters=dict(perch__smelly=True))]
[(u'bar', 1), (u'foo', 2), (u'ter', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_model(Parrot, min_count=2, filters=dict(perch__smelly=True))]
[(u'foo', 2)]
&gt;&gt;&gt; [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_model(Parrot, filters=dict(perch__size__gt=4))]
[(u'bar', False), (u'baz', False), (u'foo', False), (u'ter', False)]
&gt;&gt;&gt; [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_model(Parrot, filters=dict(perch__size__gt=99))]
[]

# Related tags
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.related_for_model(Tag.objects.filter(name__in=['bar']), Parrot, counts=True)]
[(u'baz', 1), (u'foo', 1), (u'ter', 2)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.related_for_model(Tag.objects.filter(name__in=['bar']), Parrot, min_count=2)]
[(u'ter', 2)]
&gt;&gt;&gt; [tag.name for tag in Tag.objects.related_for_model(Tag.objects.filter(name__in=['bar']), Parrot, counts=False)]
[u'baz', u'foo', u'ter']
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.related_for_model(Tag.objects.filter(name__in=['bar', 'ter']), Parrot, counts=True)]
[(u'baz', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.related_for_model(Tag.objects.filter(name__in=['bar', 'ter', 'baz']), Parrot, counts=True)]
[]

# Once again, with feeling (strings)
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.related_for_model('bar', Parrot, counts=True)]
[(u'baz', 1), (u'foo', 1), (u'ter', 2)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.related_for_model('bar', Parrot, min_count=2)]
[(u'ter', 2)]
&gt;&gt;&gt; [tag.name for tag in Tag.objects.related_for_model('bar', Parrot, counts=False)]
[u'baz', u'foo', u'ter']
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.related_for_model(['bar', 'ter'], Parrot, counts=True)]
[(u'baz', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.related_for_model(['bar', 'ter', 'baz'], Parrot, counts=True)]
[]

# Retrieving tagged objects by Model ##########################################

&gt;&gt;&gt; foo = Tag.objects.get(name='foo')
&gt;&gt;&gt; bar = Tag.objects.get(name='bar')
&gt;&gt;&gt; baz = Tag.objects.get(name='baz')
&gt;&gt;&gt; ter = Tag.objects.get(name='ter')
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, foo)
[&lt;Parrot: no more&gt;, &lt;Parrot: pining for the fjords&gt;]
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, bar)
[&lt;Parrot: late&gt;, &lt;Parrot: passed on&gt;, &lt;Parrot: pining for the fjords&gt;]

# Intersections are supported
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, [foo, baz])
[]
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, [foo, bar])
[&lt;Parrot: pining for the fjords&gt;]
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, [bar, ter])
[&lt;Parrot: late&gt;, &lt;Parrot: passed on&gt;]

# Issue 114 - Intersection with non-existant tags
&gt;&gt;&gt; TaggedItem.objects.get_intersection_by_model(Parrot, [])
[]

# You can also pass Tag QuerySets
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, Tag.objects.filter(name__in=['foo', 'baz']))
[]
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, Tag.objects.filter(name__in=['foo', 'bar']))
[&lt;Parrot: pining for the fjords&gt;]
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, Tag.objects.filter(name__in=['bar', 'ter']))
[&lt;Parrot: late&gt;, &lt;Parrot: passed on&gt;]

# You can also pass strings and lists of strings
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, 'foo baz')
[]
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, 'foo bar')
[&lt;Parrot: pining for the fjords&gt;]
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, 'bar ter')
[&lt;Parrot: late&gt;, &lt;Parrot: passed on&gt;]
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, ['foo', 'baz'])
[]
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, ['foo', 'bar'])
[&lt;Parrot: pining for the fjords&gt;]
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, ['bar', 'ter'])
[&lt;Parrot: late&gt;, &lt;Parrot: passed on&gt;]

# Issue 50 - Get by non-existent tag
&gt;&gt;&gt; TaggedItem.objects.get_by_model(Parrot, 'argatrons')
[]

# Unions
&gt;&gt;&gt; TaggedItem.objects.get_union_by_model(Parrot, ['foo', 'ter'])
[&lt;Parrot: late&gt;, &lt;Parrot: no more&gt;, &lt;Parrot: passed on&gt;, &lt;Parrot: pining for the fjords&gt;]
&gt;&gt;&gt; TaggedItem.objects.get_union_by_model(Parrot, ['bar', 'baz'])
[&lt;Parrot: late&gt;, &lt;Parrot: passed on&gt;, &lt;Parrot: pining for the fjords&gt;]

# Issue 114 - Union with non-existant tags
&gt;&gt;&gt; TaggedItem.objects.get_union_by_model(Parrot, [])
[]

# Retrieving related objects by Model #########################################

# Related instances of the same Model
&gt;&gt;&gt; l1 = Link.objects.create(name='link 1')
&gt;&gt;&gt; Tag.objects.update_tags(l1, 'tag1 tag2 tag3 tag4 tag5')
&gt;&gt;&gt; l2 = Link.objects.create(name='link 2')
&gt;&gt;&gt; Tag.objects.update_tags(l2, 'tag1 tag2 tag3')
&gt;&gt;&gt; l3 = Link.objects.create(name='link 3')
&gt;&gt;&gt; Tag.objects.update_tags(l3, 'tag1')
&gt;&gt;&gt; l4 = Link.objects.create(name='link 4')
&gt;&gt;&gt; TaggedItem.objects.get_related(l1, Link)
[&lt;Link: link 2&gt;, &lt;Link: link 3&gt;]
&gt;&gt;&gt; TaggedItem.objects.get_related(l1, Link, num=1)
[&lt;Link: link 2&gt;]
&gt;&gt;&gt; TaggedItem.objects.get_related(l4, Link)
[]

# Limit related items
&gt;&gt;&gt; TaggedItem.objects.get_related(l1, Link.objects.exclude(name='link 3'))
[&lt;Link: link 2&gt;]

# Related instance of a different Model
&gt;&gt;&gt; a1 = Article.objects.create(name='article 1')
&gt;&gt;&gt; Tag.objects.update_tags(a1, 'tag1 tag2 tag3 tag4')
&gt;&gt;&gt; TaggedItem.objects.get_related(a1, Link)
[&lt;Link: link 1&gt;, &lt;Link: link 2&gt;, &lt;Link: link 3&gt;]
&gt;&gt;&gt; Tag.objects.update_tags(a1, 'tag6')
&gt;&gt;&gt; TaggedItem.objects.get_related(a1, Link)
[]

# Limiting results to a queryset
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(state='no more'), counts=True)]
[(u'foo', 1), (u'ter', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(state__startswith='p'), counts=True)]
[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=4), counts=True)]
[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__smelly=True), counts=True)]
[(u'bar', 1), (u'foo', 2), (u'ter', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__smelly=True), min_count=2)]
[(u'foo', 2)]
&gt;&gt;&gt; [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=4))]
[(u'bar', False), (u'baz', False), (u'foo', False), (u'ter', False)]
&gt;&gt;&gt; [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=99))]
[]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')), counts=True)]
[(u'bar', 2), (u'foo', 1), (u'ter', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')), min_count=2)]
[(u'bar', 2)]
&gt;&gt;&gt; [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')))]
[(u'bar', False), (u'foo', False), (u'ter', False)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(state='passed on'), counts=True)]
[(u'bar', 2), (u'foo', 2), (u'ter', 2)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(state__startswith='p'), min_count=2)]
[(u'ter', 2)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(Q(perch__size__gt=6) | Q(perch__smelly=False)), counts=True)]
[(u'foo', 1), (u'ter', 1)]
&gt;&gt;&gt; [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(perch__smelly=True).filter(state__startswith='l'), counts=True)]
[(u'bar', 1), (u'ter', 1)]

################
# Model Fields #
################

# TagField ####################################################################

# Ensure that automatically created forms use TagField
&gt;&gt;&gt; class TestForm(forms.ModelForm):
...     class Meta:
...         model = FormTest
&gt;&gt;&gt; form = TestForm()
&gt;&gt;&gt; form.fields['tags'].__class__.__name__
'TagField'

# Recreating string representaions of tag lists ###############################
&gt;&gt;&gt; plain = Tag.objects.create(name='plain')
&gt;&gt;&gt; spaces = Tag.objects.create(name='spa ces')
&gt;&gt;&gt; comma = Tag.objects.create(name='com,ma')

&gt;&gt;&gt; from tagging.utils import edit_string_for_tags
&gt;&gt;&gt; edit_string_for_tags([plain])
u'plain'
&gt;&gt;&gt; edit_string_for_tags([plain, spaces])
u'plain, spa ces'
&gt;&gt;&gt; edit_string_for_tags([plain, spaces, comma])
u'plain, spa ces, &quot;com,ma&quot;'
&gt;&gt;&gt; edit_string_for_tags([plain, comma])
u'plain &quot;com,ma&quot;'
&gt;&gt;&gt; edit_string_for_tags([comma, spaces])
u'&quot;com,ma&quot;, spa ces'

###############
# Form Fields #
###############

&gt;&gt;&gt; t = TagField()
&gt;&gt;&gt; t.clean('foo')
u'foo'
&gt;&gt;&gt; t.clean('foo bar baz')
u'foo bar baz'
&gt;&gt;&gt; t.clean('foo,bar,baz')
u'foo,bar,baz'
&gt;&gt;&gt; t.clean('foo, bar, baz')
u'foo, bar, baz'
&gt;&gt;&gt; t.clean('foo qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvb bar')
u'foo qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvb bar'
&gt;&gt;&gt; t.clean('foo qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbn bar')
Traceback (most recent call last):
    ...
ValidationError: [u'Each tag may be no more than 50 characters long.']

</pre>

<!-- ==================== NAVIGATION BAR ==================== -->
<table class="navbar" border="0" width="100%" cellpadding="0"
       bgcolor="#a0c0ff" cellspacing="0">
  <tr valign="middle">

  <!-- Tree link -->
      <th>&nbsp;&nbsp;&nbsp;<a
        href="module-tree.html">Trees</a>&nbsp;&nbsp;&nbsp;</th>

  <!-- Index link -->
      <th>&nbsp;&nbsp;&nbsp;<a
        href="identifier-index.html">Indices</a>&nbsp;&nbsp;&nbsp;</th>

  <!-- Help link -->
      <th>&nbsp;&nbsp;&nbsp;<a
        href="help.html">Help</a>&nbsp;&nbsp;&nbsp;</th>

      <th class="navbar" width="100%"></th>
  </tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%%">
  <tr>
    <td align="left" class="footer">
    Generated by Epydoc 3.0.1 on Thu Apr  1 02:28:20 2010
    </td>
    <td align="right" class="footer">
      <a target="mainFrame" href="http://epydoc.sourceforge.net"
        >http://epydoc.sourceforge.net</a>
    </td>
  </tr>
</table>

<script type="text/javascript">
  <!--
  // Private objects are initially displayed (because if
  // javascript is turned off then we want them to be
  // visible); but by default, we want to hide them.  So hide
  // them unless we have a cookie that says to show them.
  checkCookie();
  // -->
</script>
</body>
</html>
